﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;

namespace Maze
{
    public class Maze
    {
        private static int _Rows;
        private static int _Columns;
        private static int _CellSize;

        private Cell[,] _Cells = null;
        Stack<Cell>_CellStack = new Stack<Cell>();
        Cell _CurrentNode = null;

        private int _VisitedNodes = 1;
        private int _TotalNodes;

        public Maze(int Row, int Columns, int CellSize)
        {
            _Rows = Row;
            _Columns = Columns;
            _CellSize = CellSize;
            _TotalNodes = _Rows * _Columns;
            InitializeGrid();
            GeneratePaths();
        }

        public static int Rows { get { return _Rows; } }
        public static int Columns { get { return _Columns; } }
        public static int NodeWidth { get { return _CellSize; } }

        private void InitializeGrid()
        {
            _Cells = new Cell[_Rows, _Columns];
            for (int x = 0; x < _Rows; x++)
                for (int y = 0; y < _Columns; y++)
                {
                    _Cells[x, y] = new Cell();
                    _Cells[x, y].Row = x;
                    _Cells[x, y].Column = y;
                }
            _CurrentNode = _Cells[0, 0];
            _VisitedNodes = 1;
            _CellStack.Clear();
        }

        private void GeneratePaths()
        {
            while (_VisitedNodes < _TotalNodes)
            {
                List<Cell> _AdjacentCells = GetNeighbors(_CurrentNode);
                if (_AdjacentCells.Count > 0)
                {
                    int _RandomNode = Cell.Random.Next(0, _AdjacentCells.Count);
                    Cell _Node = _AdjacentCells[_RandomNode];
                    _CurrentNode.RemoveWall(_Node);
                    _CellStack.Push(_CurrentNode);
                    _CurrentNode = _Node;
                    _VisitedNodes++;
                }
                else _CurrentNode = _CellStack.Pop();
            }
        }

        private List<Cell> GetNeighbors(Cell cell)
        {

            List<Cell> _Neighbors = new List<Cell>();
            for (int x = -1; x <= 1; x++)
                for (int y = -1; y <= 1; y++)
                {
                    if (cell.Row + x < _Rows && cell.Column + y < _Columns && cell.Row + x >= 0 &&
                        cell.Column + y >= 0 && (x == 0 || y == 0) && x != y)
                    {
                        if (_Cells[cell.Row + x, cell.Column + y].AllWallsUp())
                            _Neighbors.Add(_Cells[cell.Row + x, cell.Column + y]);
                    }
                }

            return _Neighbors;
        }

        public void Draw(Graphics _Graphics)
        {
            for (int x = 0; x < _Rows; x++)
                for (int y = 0; y < _Columns; y++)
                    _Cells[x, y].Draw(_Graphics);
        }
    }
}
